package com.gong.gongcloudpicture1.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gong.gongcloudpicture1.common.BaseResponse;
import com.gong.gongcloudpicture1.exception.BusinessException;
import com.gong.gongcloudpicture1.exception.ErrorCode;
import com.gong.gongcloudpicture1.exception.ThrowUtils;
import com.gong.gongcloudpicture1.manager.FileManager;
import com.gong.gongcloudpicture1.manager.upload.FilePictureUpload;
import com.gong.gongcloudpicture1.manager.upload.PictureUploadTemplate;
import com.gong.gongcloudpicture1.manager.upload.UrlPictureUpload;
import com.gong.gongcloudpicture1.model.dto.file.UploadPictureResult;
import com.gong.gongcloudpicture1.model.dto.picture.PictureQueryRequest;
import com.gong.gongcloudpicture1.model.dto.picture.PictureReviewRequest;
import com.gong.gongcloudpicture1.model.dto.picture.PictureUploadByBatchRequest;
import com.gong.gongcloudpicture1.model.dto.picture.PictureUploadRequest;
import com.gong.gongcloudpicture1.model.entity.picture.Picture;
import com.gong.gongcloudpicture1.model.entity.user.User;
import com.gong.gongcloudpicture1.model.enums.PictureReviewStatusEnum;
import com.gong.gongcloudpicture1.model.vo.picture.PictureVO;
import com.gong.gongcloudpicture1.model.vo.user.UserLoginVo;
import com.gong.gongcloudpicture1.model.vo.user.UserVO;
import com.gong.gongcloudpicture1.service.PictureService;
import com.gong.gongcloudpicture1.mapper.PictureMapper;
import com.gong.gongcloudpicture1.service.UserService;
import com.gong.gongcloudpicture1.util.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author g1783
 * @description 针对表【picture(图片)】的数据库操作Service实现
 * @createDate 2025-06-07 21:59:45
 */
@Service
@Slf4j
public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture> implements PictureService {


    private static final String YES = "1";
    private static final String NO = "0";


    @Resource
    private PictureMapper pictureMapper;

    @Resource
    private FileManager fileManager;

    @Resource
    private UserService userService;

    @Resource
    private FilePictureUpload filePictureUpload;

    @Resource
    private UrlPictureUpload urlPictureUpload;


    /**
     * 图片校验
     *
     * @param picture
     */
    @Override
    public void validPicture(Picture picture) {
        ThrowUtils.throwIf(picture == null, ErrorCode.PARAMS_ERROR);
        // 从对象中取值
        Long id = picture.getId();
        String url = picture.getUrl();
        String introduction = picture.getIntroduction();
        // 修改数据时，id 不能为空，有参数则校验
        ThrowUtils.throwIf(ObjUtil.isNull(id), ErrorCode.PARAMS_ERROR, "id 不能为空");
        if (StrUtil.isNotBlank(url)) {
            ThrowUtils.throwIf(url.length() > 1024, ErrorCode.PARAMS_ERROR, "url 过长");
        }
        if (StrUtil.isNotBlank(introduction)) {
            ThrowUtils.throwIf(introduction.length() > 800, ErrorCode.PARAMS_ERROR, "简介过长");
        }
    }


    /**
     * 文件上传
     *
     * @param inputSource          上传的文件
     * @param pictureUploadRequest
     * @param loginUser            当前登录用户
     * @return
     */
    @Override
    public BaseResponse<PictureVO> uploadPicture(Object inputSource, PictureUploadRequest pictureUploadRequest, User loginUser) {
        //校验参数
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        //判断新增还是删除
        Long pictureId = null;
        if (pictureUploadRequest != null) {
            pictureId = pictureUploadRequest.getId();
        }
        //如果是更新, 判断图片是否存在
        if (pictureId != null) {
            Picture picture = pictureMapper.selectOne(
                    new LambdaQueryWrapper<Picture>()
                            .eq(Picture::getId, pictureId)
                            .eq(Picture::getIsDel, NO)
            );
            if (picture == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "图片不存在!");
            }
            //只能更新本人创建的图片
            if (!picture.getUserId().equals(loginUser.getId()) && userService.isAdmin(loginUser)) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
            }
        }
        //上传图片得到图片信息
        //这里给路径前缀加上public表示当前图库是公共的, 如果以后要存放私有的, 那么可以另取名称, 然后按照用户id区分目录
        String uploadPathPrefix = String.format("/public/%s", loginUser.getId());
        //根据inputSource类型区分上传方式
        PictureUploadTemplate pictureUploadTemplate = filePictureUpload; //默认是文件上传
        if (inputSource instanceof String) { //如果是字符串
            pictureUploadTemplate = urlPictureUpload; //转给url上传
        }
        UploadPictureResult uploadPictureResult = pictureUploadTemplate.uploadPicture(inputSource, uploadPathPrefix);
        //操作数据库
        Picture picture = new Picture();
        BeanUtils.copyProperties(uploadPictureResult, picture);
        String picName = uploadPictureResult.getPicName();
        if (pictureUploadRequest != null && StringUtils.isNotBlank(pictureUploadRequest.getPicName())) {
            picName = pictureUploadRequest.getPicName();
        }
        picture.setName(picName);
        picture.setUserId(loginUser.getId());
        fillReviewStatus(picture, loginUser);
        //判断是更新还是新增图片
        if (pictureId != null) {
            //更新
            picture.setId(pictureId);
            picture.setEditTime(new Date());
        }
        boolean result = this.saveOrUpdate(picture);
        ThrowUtils.throwIf(!result, new BusinessException(ErrorCode.OPERATION_ERROR, "操作失败, 数据库异常"));
        return BaseResponse.success(PictureVO.objToVo(picture));
    }


    /**
     * 图片查询体
     *
     * @param pictureQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<Picture> getQueryWrapper(PictureQueryRequest pictureQueryRequest) {
        if (pictureQueryRequest == null) {
            return new QueryWrapper<>();
        }
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(pictureQueryRequest.getSearchText())) {
            queryWrapper.and(
                    qw -> qw.like("name", pictureQueryRequest.getName())
                            .or()
                            .like("introduction", pictureQueryRequest.getIntroduction())
            );
        }
        queryWrapper.eq(ObjectUtils.isNotEmpty(pictureQueryRequest.getId()), "id", pictureQueryRequest.getId());
        queryWrapper.like(StringUtils.isNotBlank(pictureQueryRequest.getName()), "name", pictureQueryRequest.getName());
        queryWrapper.like(StringUtils.isNotBlank(pictureQueryRequest.getIntroduction()), "introduction", pictureQueryRequest.getIntroduction());
        queryWrapper.eq(StringUtils.isNotBlank(pictureQueryRequest.getCategory()), "category", pictureQueryRequest.getCategory());
        List<String> tags = pictureQueryRequest.getTags();
        if (CollectionUtil.isNotEmpty(tags)) {
            for (String tag : tags) {
                queryWrapper.like("tags", "\"" + tag + "\"").or();
            }
        }
        queryWrapper.eq(ObjectUtils.isNotEmpty(pictureQueryRequest.getPicSize()), "pic_size", pictureQueryRequest.getPicSize());
        queryWrapper.eq(ObjectUtils.isNotEmpty(pictureQueryRequest.getPicWidth()), "pic_width", pictureQueryRequest.getPicWidth());
        queryWrapper.eq(ObjectUtils.isNotEmpty(pictureQueryRequest.getPicHeight()), "pic_height", pictureQueryRequest.getPicHeight());
        queryWrapper.eq(ObjectUtils.isNotEmpty(pictureQueryRequest.getPicScale()), "pic_scale", pictureQueryRequest.getPicScale());
        //这里判断是否是管理员, 如果是管理员则查看全部图片, 如果不是则查看审核通过的图片
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        User user = userService.getLogInUser2(request);
        if (!userService.isAdmin(user)) {
            queryWrapper.eq("review_status", PictureReviewStatusEnum.PASS.getValue());
        }
        queryWrapper.eq(ObjectUtils.isNotEmpty(pictureQueryRequest.getReviewStatus()), "review_status", pictureQueryRequest.getReviewStatus());
        //排序
        if (StringUtils.isNotBlank(pictureQueryRequest.getSortField())) {
            queryWrapper.orderBy(StringUtils.isNotBlank(pictureQueryRequest.getSortField()), pictureQueryRequest.getSortOrder().equals("ascend"), pictureQueryRequest.getSortField());
        }
        return queryWrapper;
    }


    /**
     * 获取图片VO
     *
     * @param picture
     * @return
     */
    @Override
    public PictureVO getPictureVO(Picture picture) {
        PictureVO pictureVO = new PictureVO();
        BeanUtils.copyProperties(picture, pictureVO);
        //将集合类型的JSON字符串转换成集合
        String tags = picture.getTags();
        List<String> tagList = JSONUtil.toList(tags, String.class);
        pictureVO.setTags(tagList);
        Long userId = picture.getUserId();
        if (userId != null && userId > 0) {
            User user = userService.getById(userId);
            if (user != null) {
                UserVO userVo = userService.getUserVo(user);
                pictureVO.setUser(userVo);
            }
        }
        return pictureVO;
    }


    /**
     * 获取图片VO集合
     *
     * @param pictureList
     * @return
     */
    @Override
    public List<PictureVO> getPictureVOList(List<Picture> pictureList) {
        if (CollectionUtil.isEmpty(pictureList)) {
            return new ArrayList<>();
        }
        //将用户的id整合到一个集合
        List<Long> userIdList = pictureList.stream().map(Picture::getUserId).distinct().collect(Collectors.toList());
        //批量查出用户
        List<User> userList = userService.listByIds(userIdList);
        //转换成map
        Map<Long, User> userMap = userList.stream().collect(Collectors.toMap(User::getId, user -> user));
        //转换VO集合
        List<PictureVO> pictureVOList = pictureList.stream().map(PictureVO::objToVo).collect(Collectors.toList());
        for (PictureVO pictureVO : pictureVOList) {
            User user = userMap.get(pictureVO.getUserId());
            if (user != null) {
                pictureVO.setUser(userService.getUserVo(user));
            }
        }
        return pictureVOList;
    }


    /**
     * 图片审核 管理员使用
     *
     * @param pictureReviewRequest
     */
    @Override
    public void doPictureReview(PictureReviewRequest pictureReviewRequest, HttpServletRequest request) {
        if (pictureReviewRequest == null || pictureReviewRequest.getId() == null || PictureReviewStatusEnum.getNameByValue(pictureReviewRequest.getReviewStatus()) == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //判断原数据是否存在
        Picture picture = this.getById(pictureReviewRequest.getId());
        if (picture == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        if (picture.getReviewStatus().equals(PictureReviewStatusEnum.getNameByValue(pictureReviewRequest.getReviewStatus()).getValue())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "请勿重复审批");
        }
        UserLoginVo loginUser = userService.getLogInUser(request).getData();
        //更新数据
        picture.setReviewerId(loginUser.getId());
        picture.setReviewStatus(pictureReviewRequest.getReviewStatus());
        picture.setReviewMessage(pictureReviewRequest.getReviewMessage());
        picture.setReviewTime(new Date());
        boolean result = this.updateById(picture);
        ThrowUtils.throwIf(!result, new BusinessException(ErrorCode.OPERATION_ERROR, "数据库错误"));
    }


    /**
     * 获取图片VO集合
     *
     * @param picturePage
     * @return
     */
    @Override
    public Page<PictureVO> getPictureVOPage(Page<Picture> picturePage) {
        List<Picture> records = picturePage.getRecords();
        Page<PictureVO> pictureVOPage = new Page<>(picturePage.getCurrent(), picturePage.getSize(), picturePage.getTotal());
        if (CollectionUtil.isEmpty(records)) {
            return pictureVOPage;
        }
        //将用户的id整合到一个集合
        List<Long> userIdList = records.stream().map(Picture::getUserId).distinct().collect(Collectors.toList());
        //批量查出用户
        List<User> userList = userService.listByIds(userIdList);
        //转换成map
        Map<Long, User> userMap = userList.stream().collect(Collectors.toMap(User::getId, user -> user));
        //转换VO集合
        List<PictureVO> pictureVOList = records.stream().map(PictureVO::objToVo).collect(Collectors.toList());
        for (PictureVO pictureVO : pictureVOList) {
            User user = userMap.get(pictureVO.getUserId());
            if (user != null) {
                pictureVO.setUser(userService.getUserVo(user));
            }
        }
        pictureVOPage.setRecords(pictureVOList);
        return pictureVOPage;
    }


    /**
     * 图片管理分页
     *
     * @param pictureQueryRequest
     * @return
     */
    @Override
    public Page<PictureVO> listPictureVoByPage(PictureQueryRequest pictureQueryRequest) {
        Page<Picture> picturePage = pictureMapper.selectPage(new Page<>(pictureQueryRequest.getCurrent(), pictureQueryRequest.getPageSize()), getQueryWrapper(pictureQueryRequest));
        return getPictureVOPage(picturePage);
    }


    @Override
    public void fillReviewStatus(Picture picture, User user) {
        if (userService.isAdmin(user)) {
            picture.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
            picture.setReviewerId(user.getId());
            picture.setReviewMessage("管理员自动通过审核");
            picture.setReviewerName(user.getUserName());
            picture.setReviewTime(new Date());
        } else {
            picture.setReviewStatus(PictureReviewStatusEnum.APPROVAL.getValue());
            picture.setEditTime(new Date());
        }
    }


    /**
     * 批量上传图片, 通过页面抓取
     * @param pictureUploadByBatchRequest
     * @param loginUser
     * @return
     */
    @Override
    public Integer uploadPictureByBatch(PictureUploadByBatchRequest pictureUploadByBatchRequest, User loginUser) {
        //1 校验参数
        String searchText = pictureUploadByBatchRequest.getSearchText();
        Integer count = pictureUploadByBatchRequest.getCount();
        if (count > 30) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多可以抓取30条");
        }
        //名称前缀, 如果名称前缀为空, 那么默认是搜索关键词
        String namePrefix = pictureUploadByBatchRequest.getNamePrefix();
        if (StringUtils.isBlank(namePrefix)) {
            namePrefix = searchText;
        }
        //2 抓取内容
        //设置固定地址
        String fetchPath = String.format("https://cn.bing.com/images/search?q=%s&mmasync=1", searchText);
        Document document = null;
        try {
            document = Jsoup.connect(fetchPath).get();
        } catch (IOException e) {
            log.error("页面解析失败", e);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "页面解析失败");
        }
        //3 解析内容
        Element div = document.getElementsByClass("dgControl").first();
        if (ObjUtil.isEmpty(div)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "页面元素获取失败");
        }
        Elements imgElementList = div.select("img.mimg");
        int uploadCount = 1;
        for (Element imgElement : imgElementList) {
            //取属性
            String fileUrl = imgElement.attr("src");
            if (StringUtils.isBlank(fileUrl)) {
                log.info("当前图片链接为空, 已跳过 当前序号:{}, 路径:{}", uploadCount, fileUrl);
                uploadCount++;
                continue;
            }
            //处理图片地址, 防止转义或者与对象存储有冲突
            //将 ? 后面的去掉
            int questionIndex = fileUrl.indexOf("?");
            if (questionIndex > -1) {
                fileUrl = fileUrl.substring(0, questionIndex);
            }
            //获取图片类型
            String urlType = HttpUtil.getUrlType(fileUrl);
            //4 上传图片
            //上传图片 构造请求参数
            try {
                PictureUploadRequest pictureUploadRequest = new PictureUploadRequest();
                pictureUploadRequest.setFileUrl(fileUrl + "." + urlType);
                pictureUploadRequest.setPicName(namePrefix + RandomUtil.randomString(5));
                PictureVO pictureVO = this.uploadPicture(fileUrl, pictureUploadRequest, loginUser).getData();
                log.info("序号:{}, 图片上传成功, id:{}",uploadCount, pictureVO.getId());
                uploadCount++;
            } catch (Exception e) {
                log.info("图片上传失败", e);
                uploadCount++;
                continue;
            }
            if (uploadCount >= count) {
                break;
            }
        }
        return uploadCount;
    }
}




